home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / TextPainter.C < prev    next >
C/C++ Source or Header  |  1992-08-26  |  12KB  |  485 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "TextPainter.h"
  6.  
  7. #include "Class.h"
  8. #include "Text.h"
  9. #include "Font.h"
  10. #include "WindowSystem.h"
  11. #include "TextFormatter.h"   // -> LineDesc
  12. #include "Bitmap.h"
  13. #include "Math.h"
  14.  
  15. extern bool gPrinting; // --> #include PrintManager.h
  16.  
  17. //---- output map for control characters --------------------------------------
  18.  
  19. static RGBColor *invisColor;
  20. static Font *symbolFont= 0,
  21.         *noSymbolFont= 0;
  22.  
  23. const byte o_symbol     =       01,  // use symbol font
  24.        o_grey       =       02,  // use grey color
  25.        o_dot        =       04,  // mark character with a dot
  26.        o_nomove     =      010;  // draw character without moving cp
  27.        
  28. static struct outmap {
  29.     byte c;         // 0 == don't map
  30.     byte code;   
  31. } OutMap[] = {
  32.     0xa4,     o_grey,                       /* 0x00 (0xae???) */
  33.     0,        0,                            /* 0x01 */
  34.     0,        0,                            /* 0x02 */
  35.     0,        0,                            /* 0x03 */
  36.     0,        0,                            /* 0x04 */
  37.     0,        0,                            /* 0x05 */
  38.     0,        0,                            /* 0x06 */
  39.     0,        0,                            /* 0x07 */
  40.     0,        0,                            /* 0x08 */
  41.     0xf1,     o_symbol|o_grey|o_nomove,     /* 0x09 (0xae???) */
  42.     0xa6,     o_grey,                       /* 0x0a (0xb6???) */
  43.     0,        0,                            /* 0x0b */
  44.     0xdf,     o_symbol|o_grey,              /* 0x0c */
  45.     0xbf,     o_symbol|o_grey,              /* 0x0d */
  46.     0,        0,                            /* 0x0e */
  47.     0,        0,                            /* 0x0f */
  48.     0,        0,                            /* 0x10 */
  49.     0,        0,                            /* 0x11 */
  50.     0,        0,                            /* 0x12 */
  51.     0,        0,                            /* 0x13 */
  52.     0,        0,                            /* 0x14 */
  53.     0,        0,                            /* 0x15 */
  54.     0,        0,                            /* 0x16 */
  55.     0,        0,                            /* 0x17 */
  56.     0,        0,                            /* 0x18 */
  57.     0,        0,                            /* 0x19 */
  58.     0,        0,                            /* 0x1a */
  59.     0,        0,                            /* 0x1b */
  60.     0,        0,                            /* 0x1c */
  61.     0,        0,                            /* 0x1d */
  62.     0,        0,                            /* 0x1e */
  63.     0,        0,                            /* 0x1f */
  64. };
  65.  
  66. static inline bool UseSymbolFont(byte c)
  67. {
  68.     return c&o_symbol;
  69. }
  70.  
  71. static inline bool UseGrey(byte c)
  72. {
  73.     return gColor && (c&o_grey);
  74. }
  75.  
  76. static inline bool NoMove(byte c)
  77. {
  78.     return c&o_nomove;
  79. }
  80.  
  81. //---- TextPainter ------------------------------------------------------------
  82.  
  83. NewMetaImpl(TextPainter, Object, (T(nextFontChange), TP(ps), TP(sp), T(graphicChar))); 
  84.  
  85. TextPainter::TextPainter()
  86. {
  87.     linebuf= 0;
  88. }
  89.  
  90. TextPainter::~TextPainter()
  91. {
  92.     SafeDelete(linebuf);
  93. }
  94.  
  95. void TextPainter::Init(Text *t, int from, int to)
  96. {
  97.     line= t->GetLineAccess(&linebuf, from, to);
  98.     ps= t->GetParaStyle(from);
  99.     nextFontChange= -1;
  100.     graphicChar= t->GetMarkChar();
  101. }
  102.  
  103. int TextPainter::Strip(Text *t, int from, int to)
  104. {
  105.     for ( ; to-1 >= from && ((*t)[to-1] == ' ' || (*t)[to-1] == '\t'); to--) 
  106.     ;
  107.     return to;
  108. }
  109.  
  110. int TextPainter::CalcSpace(Text *t, int width, int from, int to, 
  111.                       int &space, int &blanks, int &ntab)
  112. {
  113.     int nBlanks, ch;
  114.  
  115.     nBlanks= space= blanks= ntab= 0;
  116.     
  117.     to= Strip(t, from, to);
  118.  
  119.     int w= CalcWidth(t, from, to);
  120.     for (int i= from; i < to; i++) {
  121.     ch= line[i-from];
  122.     switch(ch) {
  123.     case '\t':
  124.         ntab++;
  125.         nBlanks= 0;
  126.         break;
  127.     case ' ':
  128.         nBlanks++;
  129.         break;
  130.     default:
  131.         ;
  132.     }
  133.     }
  134.     if (nBlanks) {
  135.     blanks= (width - w) % nBlanks;
  136.     space= (width - w) / nBlanks;
  137.     }
  138.     return to;
  139. }
  140.  
  141. int TextPainter::CalcIndent(Text *t, ParaStyle *p, int at, int &width)
  142. {
  143.     int indent= p->GetProperty(eTxtPLeft);
  144.     int findent= p->GetProperty(eTxtPFirstIndent);
  145.     int rindent= p->GetProperty(eTxtPRight);
  146.     if (t->IsParaStart(at))
  147.     indent= Math::Max(0, indent+findent);
  148.     width= width-indent-rindent;
  149.     return indent;
  150. }
  151.  
  152. bool TextPainter::IsJustified(Text *t, int eol)
  153. {
  154.     TxtParaAlign a= (TxtParaAlign)ps->GetProperty(eTxtPAlign);
  155.     byte ch= (*t)[eol-1];
  156.     return a == eTxtParaJustified && eol != t->Size() && !t->IsBreak(ch);
  157. }
  158.  
  159. void TextPainter::ShowInvisible(byte ch)
  160. {
  161.     Ink *sInk;
  162.     Point sPoint;
  163.     Font *sFont;
  164.     
  165.     byte code= OutMap[ch].code;
  166.     
  167.     if(code != 0) {
  168.     if (UseGrey(code)) {
  169.         sInk= GrGetTextInk();
  170.         if (invisColor == 0)
  171.         invisColor= new_Grey(0.5);
  172.         GrSetTextInk(invisColor);
  173.     }
  174.     if (NoMove(code))
  175.         sPoint= GrGetTextPos();
  176.     
  177.     sFont= GrGetFont();          
  178.     if (UseSymbolFont(code)) {
  179.         if (symbolFont == 0)
  180.         symbolFont= new_Font(eFontSymbol, 10);
  181.         GrSetFont(symbolFont);
  182.     } 
  183.     else {
  184.         if (noSymbolFont == 0)
  185.         noSymbolFont= new_Font(eFontTimes, 10);
  186.         GrSetFont(noSymbolFont);
  187.     }
  188.       
  189.     GrDrawChar(OutMap[ch].c);
  190.         
  191.     if (UseGrey(code))
  192.         GrSetTextInk(sInk);
  193.     if (NoMove(code))
  194.         GrTextMoveto(sPoint);        
  195.     GrSetFont(sFont);
  196.     }    
  197. }
  198.  
  199. void TextPainter::SetCharStyle(CharStyle *cs)
  200. {
  201.     GrSetFont(cs->GetFont());
  202.     GrSetTextInk(cs->GetInk());
  203. }
  204.  
  205. int TextPainter::FirstCharPos(Text *t, int width, int from, int to)
  206. {    
  207.     //---- strip trailing whitespace, blank, tab or new line
  208.     byte ch= (*t)[to-1];
  209.     if (Isspace(ch) || t->IsBreak(ch))
  210.     to= Math::Max(0, --to);
  211.  
  212.     TxtParaAlign align= (TxtParaAlign)ps->GetProperty(eTxtPAlign);
  213.     switch (align) {
  214.     case eTxtParaCenter:
  215.     return (width - CalcWidth(t, from, to))/2;
  216.     case eTxtParaRight:
  217.     return width - CalcWidth(t, from, to);
  218.     }
  219.     return 0;
  220. }
  221.  
  222. int TextPainter::CalcWidth(Text *t, int from, int to)
  223. {
  224.     int w= 0, ch, d;
  225.     int indent= CalcIndent(t, ps, from, d);
  226.     
  227.     nextFontChange= t->GetNextFontChange(from, sp);
  228.  
  229.     for (int i= from; i < to; i++) {
  230.     TestFontChange(t, i, sp);
  231.     ch= line[i-from];
  232.     if (ch == '\t') 
  233.         w+= CalcTabWidth(t, ps, w+indent, i);
  234.     else {
  235.         if (TestVisualMark(t, i, ch))
  236.         w+= t->GetVisualMarkAt(i)->GetExtent().x;
  237.         else 
  238.         w+= sp->GetFont()->Width(ch);
  239.     }
  240.     }
  241.     return w;
  242. }
  243.  
  244. void TextPainter::Draw(Text *t, Point p, int from, int to, 
  245.                      Rectangle lr, Rectangle clip, bool invis)
  246. {
  247.     register byte ch;
  248.     int ntab= 0, tabw, longBlanks= 0, addSpace= 0, seenTabs= 0;
  249.     Point left= p;
  250.     int w= lr.extent.x;
  251.     
  252.     Init(t, from, to);
  253.     bool isJust= IsJustified(t, to);
  254.     int indent= CalcIndent(t, ps, from, w);
  255.  
  256.     p.x+= FirstCharPos(t, w, from, to) + indent;
  257.     if (invis) {
  258.     if (ps->GetProperty(eTxtPNoBreak))
  259.         ShowNoBreak(p, lr, t, from, to);
  260.     if (ps->GetProperty(eTxtPKeepNext))
  261.         ShowKeepNext(p, lr, t, from, to);
  262.     }    
  263.     
  264.     if (Isspace((*t)[to-1]) && !invis)     
  265.     to= Math::Max(from, --to);
  266.     
  267.     if (isJust)
  268.     CalcSpace(t, w, from, to, addSpace, longBlanks, ntab);    
  269.     nextFontChange= t->GetNextFontChange(from, sp);
  270.     SetCharStyle(sp);
  271.     GrTextMoveto(p);
  272.     
  273.     for (int i= from, nBlanks= 0; i < to; i++) {
  274.     ch= line[i-from];
  275.     
  276.     if (invis && !gPrinting && Iscntrl(ch))
  277.         ShowInvisible(ch);
  278.         
  279.     if (TestFontChange(t, i, sp)) 
  280.         SetCharStyle(sp);
  281.  
  282.     switch (ch) {
  283.     case '\t':
  284.         tabw= CalcTabWidth(t, ps, GrGetTextPos().x-left.x, i);
  285.         GrTextAdvance(tabw);
  286.         seenTabs++;
  287.         break;
  288.  
  289.     case ' ':
  290.         GrTextAdvance(sp->GetFont()->Width(' '));
  291.         if (seenTabs == ntab) {
  292.         if (addSpace)
  293.             GrTextAdvance(addSpace);
  294.         if (nBlanks < longBlanks)
  295.             GrTextAdvance(1);
  296.         nBlanks++;
  297.         }
  298.         break;
  299.     default:
  300.         if (TestVisualMark(t, i, ch)) {
  301.         DrawVisualMark(GrGetTextPos(), 
  302.             t->GetVisualMarkAt(i), 
  303.             clip,
  304.             lr,
  305.             invis && !gPrinting
  306.         );
  307.         nextFontChange= t->GetNextFontChange(i, sp); 
  308.         SetCharStyle(sp);
  309.         } else if (!Iscntrl(ch))
  310.         GrDrawChar(ch);
  311.     }
  312.     }        
  313. }
  314.  
  315. void TextPainter::DrawVisualMark(Point p, VisualMark *vmp, Rectangle clip, Rectangle lr, bool border)
  316. {   
  317.     p.y-= vmp->Base();
  318.     Point tp= GrGetTextPos();
  319.     vmp->Draw(p, clip, lr, border);
  320.     tp.x += vmp->GetExtent().x;
  321.     GrTextMoveto(tp);
  322. }
  323.  
  324. int TextPainter::Map(Text *t, int from, int to, int stop, int x, 
  325.                                 int width, int *posX)
  326. {
  327.     register byte ch;
  328.     int ntab= 0, longBlanks= 0, addSpace= 0, seenTabs= 0, cx= 0, wx= 0;
  329.     
  330.     Init(t, from, to);
  331.     int indent= CalcIndent(t, ps, from, width);
  332.     
  333.     int fx= FirstCharPos(t, width, from, to) + indent;
  334.     bool isJust= IsJustified(t, to);
  335.     
  336.     // make new lines at end of line not selectable
  337.     ch= (*t)[to-1];
  338.     if (to-from != 0 && (t->IsBreak(ch)))
  339.     to--;
  340.     
  341.     x-= fx;
  342.         
  343.     if (isJust)
  344.     to= CalcSpace(t, width, from, to, addSpace, longBlanks, ntab);
  345.         
  346.     nextFontChange= t->GetNextFontChange(from, sp);
  347.  
  348.     for (int i= from, nBlanks= 0; i < to && i < stop; i++) {
  349.     TestFontChange(t, i, sp); 
  350.     switch (ch= line[i-from]) {
  351.     case '\t':
  352.         wx= CalcTabWidth(t, ps, cx+indent, i);
  353.         seenTabs++;
  354.         break;
  355.     case ' ':
  356.         wx= sp->GetFont()->Width(' ');
  357.         if (seenTabs == ntab) {
  358.         wx += addSpace;
  359.         if (nBlanks < longBlanks)
  360.             wx++; 
  361.         nBlanks++;
  362.         }
  363.         break;
  364.     default:
  365.         if (TestVisualMark(t, i,ch)) 
  366.         wx= t->GetVisualMarkAt(i)->GetExtent().x;
  367.         else 
  368.         wx= sp->GetFont()->Width(ch); 
  369.         break;
  370.     }
  371.     if (cx + (wx/2) > x)
  372.         break;
  373.     cx+= wx;
  374.     }
  375.     if (posX)
  376.     *posX= cx+fx;
  377.     return i;
  378.  
  379. int TextPainter::GetFormatWidth(Text *t, int at, int width)
  380. {
  381.     CalcIndent(t, t->GetParaStyle(at), at, width);
  382.     return width;
  383. }
  384.  
  385. int TextPainter::LineWidth(Text *t, int from, int to)
  386. {
  387.     Init(t, from, to);
  388.     if (t->IsBreak((*t)[to-1]))
  389.     to= Math::Max(0, --to);
  390.     return CalcWidth(t, from, to);
  391. }
  392.  
  393. void TextPainter::LineHeight(Text *t, LineDesc &ld, int start, int end)
  394. {
  395.     ps= t->GetParaStyle(start);
  396.     int sp= ps->GetProperty(eTxtPSpacing);
  397.     int d= sp-ld.lnHeight;
  398.     if (d > 0) {
  399.     ld.lnHeight+= d;
  400.     ld.lnAscent+= d; 
  401.     }
  402.     if (t->IsParaStart(start)) {
  403.     int sb= ps->GetProperty(eTxtPSpaceBefore);
  404.     ld.lnHeight+= sb;
  405.     ld.lnAscent+= sb;
  406.     }
  407.     if (t->IsParaEnd(end-1)) {
  408.     int sa= ps->GetProperty(eTxtPSpaceAfter);
  409.     ld.lnHeight+= sa;
  410.     }
  411. }
  412.  
  413. int TextPainter::CalcTabWidth(Text *t, ParaStyle *p, int x, int at)
  414. {
  415.     const ParaTabs &tabs= ps->GetTabs();
  416.     int indent= p->GetProperty(eTxtPLeft);
  417.     TxtParaAlign align= (TxtParaAlign)p->GetProperty(eTxtPAlign);
  418.     int tx, w= 0;
  419.     
  420.     // tabs are only interpreted if text is left aligned
  421.     if (align != eTxtParaLeft && align != eTxtParaJustified)
  422.     return 0;
  423.        
  424.     for(int i= 0; i < tabs.ntabs; i++) {
  425.     tx= tabs.stops[i].x;
  426.     if (tx > x) {
  427.         // indent is an implizit tab stop (flush left)
  428.         if (indent > x)
  429.         return indent-x;
  430.         else
  431.         switch(tabs.stops[i].kind) {
  432.         case eTxtTLeft:
  433.             return tx-x;
  434.         case eTxtTRight:
  435.             w= TabColWidth(t, at, "\t");
  436.             return (Math::Max(0, tx-x-w));
  437.         case eTxtTCenter:
  438.             w= TabColWidth(t, at, "\t");
  439.             return (Math::Max(0, tx-x-(w/2)));
  440.         case eTxtTDecimal:
  441.             w= TabColWidth(t, at, "\t.");
  442.             return (Math::Max(0, tx-x-w));
  443.         }
  444.     }      
  445.     }
  446.     // default tabs
  447.     int tw= t->GetDefTab();
  448.     if (indent > x)
  449.     return indent-x;
  450.     if (tw > 0)
  451.     return (((x / tw)+1) * tw - x);
  452.     return 0;
  453. }
  454.  
  455. int TextPainter::TabColWidth(Text *t, int start, char *stops)
  456. {
  457.     int w= 0, wn, ch;
  458.     AutoTextIter next(t, start+1);
  459.  
  460.     while(ch= next(&wn))
  461.     if (ch == cEOT || strchr(stops, ch) != 0 || Text::IsBreak(ch))
  462.         break;
  463.     else
  464.         w+= wn;
  465.     return w;
  466. }
  467.  
  468. int TextPainter::Tabulate(Text *t, int x, int at, int lineStart)
  469. {
  470.     int w;
  471.     ps= t->GetParaStyle(at);
  472.     int indent= CalcIndent(t, ps, lineStart, w);
  473.     return CalcTabWidth(t, ps, x+indent, at);
  474. }
  475.  
  476. void TextPainter::ShowNoBreak(Point, Rectangle, Text *, int, int)
  477. {
  478. }
  479.  
  480. void TextPainter::ShowKeepNext(Point, Rectangle, Text *, int, int)
  481. {
  482. }
  483.  
  484.